package com.lujieni.springboothutool.utils;

import cn.hutool.core.util.ReflectUtil;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

/**
 * 反射字段操作工具类
 * 使用Hutool反射工具实现对象字段的递归查找和替换
 *
 * @author lujieni
 */
public class ReflectionFieldUtil {

    /**
     * 已处理对象集合，用于避免循环引用导致的无限递归
     *
     * class Parent {
     *     String name;
     *     Child child;
     * }
     *
     * class Child {
     *     String name;
     *     Parent parent;  // 反向引用父对象
     * }
     *
     * Parent p = new Parent();
     * Child c = new Child();
     * p.child = c;
     * c.parent = p;  // 形成循环
     *
     * // 如果没有 PROCESSED_OBJECTS，递归会无限循环：
     * // Parent -> Child -> Parent -> Child -> ...
     *
     *
     *
     */
    private static final ThreadLocal<Set<Object>> PROCESSED_OBJECTS = ThreadLocal.withInitial(HashSet::new);

    /**
     * 根据字段名递归查找并替换字段值
     *
     * @param targetObject 目标对象
     * @param fieldName    要匹配的字段名
     * @param newValue     新的String值
     */
    public static void replaceFieldValue(Object targetObject, String fieldName, String newValue) {
        if (targetObject == null || fieldName == null || fieldName.isEmpty()) {
            return;
        }

        try {
            replaceFieldValueRecursive(targetObject, fieldName, newValue);
        } finally {
            PROCESSED_OBJECTS.remove();
        }
    }

    /**
     * 递归处理对象字段
     *
     * @param targetObject 目标对象
     * @param fieldName    要匹配的字段名
     * @param newValue     新的String值
     */
    private static void replaceFieldValueRecursive(Object targetObject, String fieldName, String newValue) {
        if (targetObject == null) {
            return;
        }

        // 避免循环引用
        if (PROCESSED_OBJECTS.get().contains(targetObject)) {
            return;
        }
        PROCESSED_OBJECTS.get().add(targetObject);

        Class<?> clazz = targetObject.getClass();

        // 跳过Java内置类型和包装类
        if (isJavaInternalClass(clazz)) {
            return;
        }

        // 获取所有字段（包括父类字段）
        Field[] fields = ReflectUtil.getFields(clazz);

        for (Field field : fields) {
            try {
                // 设置字段可访问
                field.setAccessible(true);

                String currentFieldName = field.getName();
                Object fieldValue = ReflectUtil.getFieldValue(targetObject, field);

                // 如果字段名匹配直接进行替换操作
                if (currentFieldName.equals(fieldName)) {
                    processMatchedField(targetObject, field, newValue);
                    continue;
                }

                // 递归处理嵌套对象
                if (fieldValue != null) {
                    processNestedObject(fieldValue, fieldName, newValue);
                }

            } catch (Exception e) {
                // 忽略无法访问的字段
            }
        }
    }

    /**
     * 处理匹配的字段
     *
     * @param targetObject 目标对象
     * @param field        匹配的字段
     * @param newValue     新值
     */
    private static void processMatchedField(Object targetObject, Field field, String newValue) {
        Class<?> fieldType = field.getType();

        // 先设置为null
        ReflectUtil.setFieldValue(targetObject, field, null);

        // 根据字段类型进行赋值
        if (fieldType == String.class) {
            // String类型：直接赋值
            ReflectUtil.setFieldValue(targetObject, field, newValue);
        } else if (List.class.isAssignableFrom(fieldType)) {
            // List.class.isAssignableFrom(fieldType)  fieldType是否是List的子类或者是它的实现类
            // List类型：检查泛型是否为String
            Type genericType = field.getGenericType();
            if (genericType instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) genericType;
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();

                if (actualTypeArguments.length > 0 && actualTypeArguments[0] == String.class) {
                    // List<String>类型：创建新List并添加值
                    List<String> newList = new ArrayList<>();
                    newList.add(newValue);
                    ReflectUtil.setFieldValue(targetObject, field, newList);
                }
            }
        }
    }

    /**
     * 处理嵌套对象
     *
     * @param fieldValue 字段值（可能是嵌套对象、集合等）
     * @param fieldName  要匹配的字段名
     * @param newValue   新值
     */
    private static void processNestedObject(Object fieldValue, String fieldName, String newValue) {
        Class<?> fieldClass = fieldValue.getClass();

        // 处理集合类型（优先处理，即使是Java内置类）
        if (fieldValue instanceof Collection) {
            Collection<?> collection = (Collection<?>) fieldValue;
            for (Object item : collection) {
                if (item != null && !isJavaInternalClass(item.getClass())) {
                    replaceFieldValueRecursive(item, fieldName, newValue);
                }
            }
        }
        // 处理Map类型（优先处理，即使是Java内置类）
        else if (fieldValue instanceof Map) {
            Map<?, ?> map = (Map<?, ?>) fieldValue;
            for (Object value : map.values()) {
                if (value != null && !isJavaInternalClass(value.getClass())) {
                    replaceFieldValueRecursive(value, fieldName, newValue);
                }
            }
        }
        // 处理数组类型
        else if (fieldClass.isArray()) {
            Object[] array = (Object[]) fieldValue;
            for (Object item : array) {
                if (item != null && !isJavaInternalClass(item.getClass())) {
                    replaceFieldValueRecursive(item, fieldName, newValue);
                }
            }
        }
        // 跳过Java内置类型
        else if (isJavaInternalClass(fieldClass)) {
            return;
        }
        // 处理自定义对象
        else {
            replaceFieldValueRecursive(fieldValue, fieldName, newValue);
        }
    }

    /**
     * 判断是否为Java内置类或基本类型包装类
     *
     * @param clazz 类对象
     * @return 是否为Java内置类
     */
    private static boolean isJavaInternalClass(Class<?> clazz) {
        if (clazz == null) {
            return true;
        }

        // 基本类型及其包装类
        if (clazz.isPrimitive() || clazz == String.class ||
                clazz == Integer.class || clazz == Long.class ||
                clazz == Double.class || clazz == Float.class ||
                clazz == Boolean.class || clazz == Byte.class ||
                clazz == Character.class || clazz == Short.class) {
            return true;
        }

        // Java内置包
        String packageName = clazz.getPackage() != null ? clazz.getPackage().getName() : "";
        return packageName.startsWith("java.") || packageName.startsWith("javax.") ||
                packageName.startsWith("sun.") || packageName.startsWith("jdk.");
    }
}
